package controllers

import (
    "gouniapp/configs"
	"fmt"
	"log"
	"net/http"
	"time"
	"regexp"
	"os"
    "gopkg.in/yaml.v3"
	"strings"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"github.com/google/uuid"
	"github.com/golang-jwt/jwt/v5"
)

var (
    hxkey   = []byte("verification-kzh")    // 核销专用密钥
    jwtKey  = []byte("ydzxkzh")             // 用户认证密钥
)

// 用户Claims结构
type Claims struct {
	UserID   uint   `json:"uid"`
	Username string `json:"username"`
	Name     string `json:"name"`
	Role     string `json:"role"`
	OpenID   string `json:"openid"`
	Points   uint   `json:"points"`
	LastCheckIn *time.Time `json:"last_checkin"`
	jwt.RegisteredClaims
}

// 核销专用Claims结构
type VerificationClaims struct {
	FormID uint   `json:"formId"`
	RowID  uint   `json:"rowId"`
	Salt   string `json:"salt"`
	jwt.RegisteredClaims
}

// 生成核销码（使用独立签名密钥）
func GenerateVerificationCode(formID, rowID uint) string {
	salt := uuid.NewString()[:6] // 自动处理错误
	claims := VerificationClaims{
		FormID: formID,
		RowID:  rowID,
		Salt:   salt,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(240 * time.Hour)), //10天内有效
			Issuer:    "verification_system",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(hxkey)
	if err != nil {
		log.Printf("生成核销码失败: %v", err)
		return ""
	}
	return tokenString
}

// 解析核销码
func ParseVerificationToken(tokenStr string) (*VerificationClaims, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &VerificationClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return hxkey, nil
		})
	if err != nil || !token.Valid {
		return nil, fmt.Errorf("无效的核销码")
	}

	if claims, ok := token.Claims.(*VerificationClaims); ok {
		return claims, nil
	}
	return nil, fmt.Errorf("核销码解析失败")
}

// 生成用户Token
func GenerateToken(user *configs.User) (string, error) {
	expirationTime := time.Now().Add(24*7 * time.Hour)  //7天内保持登录
	claims := &Claims{
		UserID:   user.ID,
		Username: user.Username,
		Name:     user.Name,
		Role:     user.Role,
		Points:   user.Points,
		OpenID:   user.OpenID,
		LastCheckIn: user.LastCheckIn,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expirationTime),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(jwtKey)
}

// 解析用户Token
func ParseToken(tokenStr string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	if err != nil || !token.Valid {
		return nil, fmt.Errorf("无效的凭证")
	}
	return token.Claims.(*Claims), nil
}

// JWT强制登录中间件
func JWTMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := c.GetHeader("Authorization")
		if tokenStr == "" {
			JsonResponse(c, http.StatusUnauthorized, "请重新登录", nil)
			c.Abort()
			return
		}
		// 去掉 "Bearer " 前缀
		if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
			tokenStr = tokenStr[7:]
		}
		claims, err := ParseToken(tokenStr)
		if err != nil {
			JsonResponse(c, http.StatusUnauthorized, "请重新登录", nil)
			c.Abort()
			return
		}
		// 存储精简后的用户信息
		c.Set("user", &configs.User{
			ID:       claims.UserID,
			Username: claims.Username,
			Name:     claims.Name,
			Role:     claims.Role,
			Points:   claims.Points,
			LastCheckIn: claims.LastCheckIn,
			OpenID:   claims.OpenID,
		})
		c.Next()
	}
}

// JWT可选登录中间件
func OptionalJWTMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenStr := c.GetHeader("Authorization")
        if tokenStr == "" {
            c.Next()
            return
        }
        // 去除Bearer前缀
        if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
            tokenStr = tokenStr[7:]
        }
        claims, err := ParseToken(tokenStr)
        if err != nil {
            // 解析失败，继续处理请求，不中断
            c.Next()
            return
        }
        // 存储用户信息到上下文
        c.Set("user", &configs.User{
            ID:         claims.UserID,
            Username:   claims.Username,
            Name:       claims.Name,
            Role:       claims.Role,
            Points:     claims.Points,
            LastCheckIn: claims.LastCheckIn,
            OpenID:     claims.OpenID,
        })
        c.Next()
    }
}

// 权限缓存
type RouteConfig struct {
    StaticRoutes  map[string][]string // key: "METHOD|PATH", value: allowed roles
    DynamicRoutes []struct {
        Method  string
        Pattern *regexp.Regexp
        Roles   []string
    }
}
var routeConfig RouteConfig
//权限初始化
func InitPermissions() {
    viper.SetConfigFile("permissions.yaml")
    if err := viper.ReadInConfig(); err != nil {
        log.Fatal("加载权限配置失败:", err)
    }
    routeConfig.StaticRoutes = make(map[string][]string)
    var routes map[string]struct {
        Path         string
        Method       string
        AllowedRoles []string `mapstructure:"roles"`
    }
    viper.UnmarshalKey("routes", &routes)
    for _, cfg := range routes {
        // 处理动态路由
        if strings.Contains(cfg.Path, "*") {
            pattern := regexp.MustCompile("^" + strings.ReplaceAll(cfg.Path, "*", ".*") + "$")
            routeConfig.DynamicRoutes = append(routeConfig.DynamicRoutes, struct {
                Method  string
                Pattern *regexp.Regexp
                Roles   []string
            }{
                Method:  strings.ToUpper(cfg.Method),
                Pattern: pattern,
                Roles:   cfg.AllowedRoles,
            })
        } else {
            key := strings.ToUpper(cfg.Method) + "|" + cfg.Path
            routeConfig.StaticRoutes[key] = cfg.AllowedRoles
        }
    }
}

// 权限校验中间件
func RBACMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取请求信息
        path := c.FullPath()
        method := c.Request.Method
        // 获取用户角色
        user := GetCurrentUser(c)
        if user == nil {
            c.AbortWithStatusJSON(401, gin.H{"code": 401, "message": "认证失败"})
            return
        }
        // 静态路由检查
        staticKey := strings.ToUpper(method) + "|" + path
        if allowedRoles, exist := routeConfig.StaticRoutes[staticKey]; exist {
            if contains(allowedRoles, user.Role) {
                c.Next()
                return
            }
            c.AbortWithStatusJSON(403, gin.H{"code": 403, "message":  "权限不足"+path})
            return
        }
        // 动态路由检查
        for _, dr := range routeConfig.DynamicRoutes {
            if dr.Method == strings.ToUpper(method) && dr.Pattern.MatchString(path) {
                if contains(dr.Roles, user.Role) {
                    c.Next()
                    return
                }
                c.AbortWithStatusJSON(403, gin.H{"code": 403, "message": "权限不足"+path})
                return
            }
        }
        // 未配置路由默认拒绝
        c.AbortWithStatusJSON(403, gin.H{"code":403,"message": "未授权的访问路径"+path})
    }
}

// 检查是否包含角色
func contains(roles []string, target string) bool {
    for _, role := range roles {
        if role == target {
            return true
        }
    }
    return false
}

// 从上下文获取完整用户信息
func GetCurrentUser(c *gin.Context) *configs.User {
    userObj, exists := c.Get("user")
    if !exists {
        return nil
    }
    if user, ok := userObj.(*configs.User); ok {
        return user
    }
    return nil
}

// 权限编辑 配置数据结构
type PermissionConfig struct {
    Routes map[string]struct {
        Path   string   `yaml:"path"`
        Method string   `yaml:"method"`
        Roles  []string `yaml:"roles"`
        Desc   string   `yaml:"desc"`
    } `yaml:"routes"`
}

// 获取配置接口
func GetPermissions(c *gin.Context) {
    // 获取用户角色
    user := GetCurrentUser(c)
    if user == nil {
        JsonResponse(c, http.StatusInternalServerError, "请先登录", nil)
        return
    }
    if user.Role != "admin" {
        JsonResponse(c, http.StatusInternalServerError, "无权操作", nil)
        return
    }
    var config PermissionConfig
    // 读取YAML文件
    yamlFile, err := os.ReadFile("permissions.yaml")
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "无法读取配置文件", nil)
        return
    }
    if err := yaml.Unmarshal(yamlFile, &config); err != nil {
        JsonResponse(c, http.StatusInternalServerError, "配置文件解析失败", nil)
        return
    }
    JsonResponse(c, http.StatusOK, "配置获取成功", config)
}

// 保存配置接口
func SavePermissions(c *gin.Context) {
    var newConfig PermissionConfig
    if err := c.ShouldBindJSON(&newConfig); err != nil {
        JsonResponse(c, http.StatusInternalServerError, "参数错误", nil)
        return
    }
    // 转换为YAML格式
    yamlData, err := yaml.Marshal(newConfig)
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "配置序列化失败", nil)
        return
    }
    // 获取用户角色
    user := GetCurrentUser(c)
    if user == nil {
        JsonResponse(c, http.StatusInternalServerError, "请先登录", nil)
        return
    }
    if user.Role != "admin" {
        JsonResponse(c, http.StatusInternalServerError, "无权操作", nil)
        return
    }
    // 保存到文件
    if err := os.WriteFile("permissions.yaml", yamlData, 0644); err != nil {
        JsonResponse(c, http.StatusInternalServerError, "文件保存失败", nil)
        return
    }
    JsonResponse(c, http.StatusOK, "配置更新成功", newConfig)
}

// 获取序列号并返回给前端
func GetSN(ctx *gin.Context) {
    var requestData configs.Sndata
    if err := ctx.ShouldBindJSON(&requestData); err != nil {
        JsonResponse(ctx, http.StatusInternalServerError, "参数错误", nil)
        return
    }
    // 获取用户角色
    user := GetCurrentUser(ctx)
    if user == nil {
        JsonResponse(ctx, http.StatusInternalServerError, "请先登录", nil)
        return
    }
    if user.Role != "admin" {
        JsonResponse(ctx, http.StatusInternalServerError, "无权操作", nil)
        return
    }
    if err := configs.ValidateSNRequestData(&requestData); err != nil {
        JsonResponse(ctx, http.StatusInternalServerError, err.Error(), nil)
        return
    }
    if configs.Config.GetString("server.sn") != configs.GanfangSN {
        JsonResponse(ctx, http.StatusInternalServerError, "非官方授权服务器", nil)
        return
    }
    sn := configs.GenerateSerialNumber(requestData.Sysid, requestData.Day)
    JsonResponse(ctx, http.StatusOK, "获取成功", sn)
}

//统一返回
func JsonResponse(c *gin.Context, statusCode int, message string, data interface{}) {
	c.JSON(statusCode, gin.H{
		"code":    statusCode,
		"message": message,
		"data":    data,
	})
}